<template>
<<<<<<< HEAD
  <div class="reviews-container">
    <el-table :data="reviews" v-loading="loading">
      <el-table-column prop="orderId" label="订单号" width="180" />
      <el-table-column prop="productName" label="商品名称" width="120" />
      <el-table-column prop="user" label="用户" width="100" />
      <el-table-column prop="content" label="评价内容" />
      <el-table-column prop="rating" label="评分" width="80">
        <template #default="{row}">
          <el-rate v-model="row.rating" disabled />
        </template>
      </el-table-column>
      <el-table-column prop="date" label="评价时间" width="180" />
    </el-table>
=======
  <div class="reviews-management">
    <!-- 评价统计 -->
    <el-row :gutter="20" class="stats-row">
      <el-col :span="6">
        <el-card shadow="hover" class="stat-card good">
          <div class="stat-content">
            <div class="stat-icon">
              <el-icon><Star /></el-icon>
            </div>
            <div class="stat-info">
              <div class="stat-number">{{ reviewStats.good }}</div>
              <div class="stat-label">好评</div>
              <div class="stat-rate">{{ ((reviewStats.good / reviewStats.total) * 100).toFixed(1) }}%</div>
            </div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card shadow="hover" class="stat-card medium">
          <div class="stat-content">
            <div class="stat-icon">
              <el-icon><StarFilled /></el-icon>
            </div>
            <div class="stat-info">
              <div class="stat-number">{{ reviewStats.medium }}</div>
              <div class="stat-label">中评</div>
              <div class="stat-rate">{{ ((reviewStats.medium / reviewStats.total) * 100).toFixed(1) }}%</div>
            </div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card shadow="hover" class="stat-card bad">
          <div class="stat-content">
            <div class="stat-icon">
              <el-icon><Warning /></el-icon>
            </div>
            <div class="stat-info">
              <div class="stat-number">{{ reviewStats.bad }}</div>
              <div class="stat-label">差评</div>
              <div class="stat-rate">{{ ((reviewStats.bad / reviewStats.total) * 100).toFixed(1) }}%</div>
            </div>
          </div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card shadow="hover" class="stat-card total">
          <div class="stat-content">
            <div class="stat-icon">
              <el-icon><ChatDotRound /></el-icon>
            </div>
            <div class="stat-info">
              <div class="stat-number">{{ reviewStats.total }}</div>
              <div class="stat-label">总评价</div>
              <div class="stat-rate">平均{{ reviewStats.avgScore }}分</div>
            </div>
          </div>
        </el-card>
      </el-col>
    </el-row>

    <!-- 评价列表 -->
    <el-card shadow="hover" class="reviews-card">
      <template #header>
        <div class="card-header">
          <span>客户评价</span>
          <div class="header-actions">
            <el-select v-model="filterRating" placeholder="评分筛选" style="width: 120px; margin-right: 10px;">
              <el-option label="全部" value="all" />
              <el-option label="5星" value="5" />
              <el-option label="4星" value="4" />
              <el-option label="3星" value="3" />
              <el-option label="2星" value="2" />
              <el-option label="1星" value="1" />
            </el-select>
            <el-button type="primary" @click="refreshReviews">
              <el-icon><Refresh /></el-icon>
              刷新
            </el-button>
            <el-button @click="exportReviews">
              <el-icon><Download /></el-icon>
              导出
            </el-button>
          </div>
        </div>
      </template>

      <div class="reviews-list">
        <div v-for="review in filteredReviews" :key="review.id" class="review-item">
          <div class="review-header">
            <div class="customer-info">
              <div class="customer-name">{{ review.customerName }}</div>
              <div class="order-info">订单号：{{ review.orderId }}</div>
            </div>
            <div class="review-meta">
              <el-rate
                v-model="review.rating"
                disabled
                show-score
                text-color="#ff9900"
                score-template="{value}分"
              />
              <div class="review-time">{{ review.createTime }}</div>
            </div>
          </div>

          <div class="review-content">
            <div class="review-text">{{ review.content }}</div>
            <div v-if="review.tags && review.tags.length > 0" class="review-tags">
              <el-tag
                v-for="tag in review.tags"
                :key="tag"
                size="small"
                :type="getReviewTagType(tag)"
              >
                {{ tag }}
              </el-tag>
            </div>
          </div>

          <div class="review-actions">
            <div class="action-buttons">
              <el-button
                v-if="!review.reply"
                type="primary"
                size="small"
                @click="showReplyDialog(review)"
              >
                回复
              </el-button>
              <el-button
                v-if="review.rating <= 2"
                type="warning"
                size="small"
                @click="handleAppealReview(review)"
              >
                申诉
              </el-button>
            </div>
          </div>

          <!-- 商家回复 -->
          <div v-if="review.reply" class="merchant-reply">
            <div class="reply-header">
              <span class="reply-label">商家回复：</span>
              <span class="reply-time">{{ review.replyTime }}</span>
            </div>
            <div class="reply-content">{{ review.reply }}</div>
          </div>
        </div>

        <div v-if="filteredReviews.length === 0" class="empty-reviews">
          <el-empty description="暂无评价数据" />
        </div>
      </div>

      <!-- 分页 -->
      <div v-if="totalReviews > 0" class="pagination-wrapper">
        <el-pagination
          v-model:current-page="currentPage"
          v-model:page-size="pageSize"
          :page-sizes="[10, 20, 50, 100]"
          :total="totalReviews"
          layout="total, sizes, prev, pager, next, jumper"
          @size-change="getReviewsData"
          @current-change="getReviewsData"
        />
      </div>
    </el-card>

    <!-- 回复对话框 -->
    <el-dialog
      v-model="replyDialogVisible"
      title="回复客户评价"
      width="500px"
      @close="resetReplyForm"
    >
      <div class="reply-review-info">
        <div class="review-summary">
          <div class="customer-name">{{ currentReview?.customerName }}</div>
          <el-rate
            v-model="currentReview?.rating"
            disabled
            show-score
            text-color="#ff9900"
            score-template="{value}分"
          />
        </div>
        <div class="review-content">{{ currentReview?.content }}</div>
      </div>

      <el-form
        ref="replyFormRef"
        :model="replyForm"
        :rules="replyRules"
        label-width="80px"
      >
        <el-form-item label="回复内容" prop="content">
          <el-input
            v-model="replyForm.content"
            type="textarea"
            placeholder="请输入回复内容，真诚回应客户的评价"
            :rows="4"
            maxlength="500"
            show-word-limit
          />
        </el-form-item>
      </el-form>

      <template #footer>
        <span class="dialog-footer">
          <el-button @click="replyDialogVisible = false">取消</el-button>
          <el-button type="primary" :loading="replySubmitting" @click="submitReply">
            发送回复
          </el-button>
        </span>
      </template>
    </el-dialog>
>>>>>>> c61637f (所有前后端正常登录)
  </div>
</template>

<script setup>
<<<<<<< HEAD
import { ref, onMounted } from 'vue'
import { getReviews } from '@/api/reviews'

const reviews = ref([])
const loading = ref(false)
const error = ref(null)

onMounted(async () => {
  try {
    loading.value = true
    const { data } = await getReviews()
    reviews.value = data
  } catch (err) {
    error.value = err.message || '获取评价数据失败'
    console.error('获取评价数据失败:', err)
  } finally {
    loading.value = false
  }
=======
import { ref, reactive, computed, onMounted, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
  Star,
  StarFilled,
  Warning,
  ChatDotRound,
  Refresh,
  Download
} from '@element-plus/icons-vue'
import {
  getReviewsList,
  getReviewStats,
  replyReview,
  appealReview,
  getReplyTemplates,
  exportReviewsData,
  getReviewAnalysis,
  REVIEW_TYPES,
  REVIEW_TYPE_TEXT,
  REVIEW_TYPE_COLOR,
  REVIEW_TAGS,
  getReviewType,
  getRatingText,
  getRatingColor,
  getTagType,
  calculateGoodReviewRate,
  calculateAverageRating
} from '@/api/reviews'

// 响应式数据
const loading = ref(false)
const filterRating = ref('all')
const currentPage = ref(1)
const pageSize = ref(10)

// 评价统计
const reviewStats = reactive({
  good: 0,
  medium: 0,
  bad: 0,
  total: 0,
  avgScore: 0
})

// 评价列表
const reviews = ref([])
const totalReviews = ref(0)

// 回复对话框
const replyDialogVisible = ref(false)
const replySubmitting = ref(false)
const currentReview = ref(null)
const replyFormRef = ref()
const replyForm = reactive({
  content: ''
})

// 回复表单验证规则
const replyRules = {
  content: [
    { required: true, message: '请输入回复内容', trigger: 'blur' },
    { min: 10, message: '回复内容至少10个字符', trigger: 'blur' }
  ]
}

// 计算属性
const filteredReviews = computed(() => {
  if (filterRating.value === 'all') {
    return reviews.value
  }
  return reviews.value.filter(review => review.rating === parseInt(filterRating.value))
})

// 获取评价统计数据
const getReviewStatsData = async () => {
  try {
    const response = await getReviewStats()
    if (response.code === 200) {
      const data = response.data
      reviewStats.good = data.good || 0
      reviewStats.medium = data.medium || 0
      reviewStats.bad = data.bad || 0
      reviewStats.total = data.total || 0
      reviewStats.avgScore = data.avgScore || 0
    } else {
      throw new Error(response.message || '获取评价统计失败')
    }
  } catch (error) {
    console.error('获取评价统计失败:', error)
    ElMessage.error(error.message || '获取评价统计失败')
  }
}

// 获取评价列表数据
const getReviewsData = async () => {
  try {
    loading.value = true
    const params = {
      page: currentPage.value - 1,
      size: pageSize.value,
      rating: filterRating.value !== 'all' ? filterRating.value : undefined
    }

    const response = await getReviewsList(params)
    if (response.code === 200) {
      reviews.value = response.data.records || response.data || []
      totalReviews.value = response.data.total || reviews.value.length
    } else {
      throw new Error(response.message || '获取评价列表失败')
    }
  } catch (error) {
    console.error('获取评价列表失败:', error)
    ElMessage.error(error.message || '获取评价列表失败')
    reviews.value = []
    totalReviews.value = 0
  } finally {
    loading.value = false
  }
}

// 方法
const getReviewTagType = (tag) => {
  return getTagType(tag)
}

// 显示回复对话框
const showReplyDialog = (review) => {
  currentReview.value = review
  replyDialogVisible.value = true
}

// 重置回复表单
const resetReplyForm = () => {
  if (replyFormRef.value) {
    replyFormRef.value.resetFields()
  }
  replyForm.content = ''
  currentReview.value = null
}

// 提交回复
const submitReply = async () => {
  if (!replyFormRef.value) return

  await replyFormRef.value.validate(async (valid) => {
    if (valid) {
      try {
        replySubmitting.value = true

        const response = await replyReview(currentReview.value.id, {
          content: replyForm.content
        })

        if (response.code === 200) {
          // 更新评价状态
          currentReview.value.reply = replyForm.content
          currentReview.value.replyTime = new Date().toLocaleString()

          ElMessage.success('回复已发送')
          replyDialogVisible.value = false
          resetReplyForm()

          // 刷新评价列表
          await getReviewsData()
        } else {
          throw new Error(response.message || '回复发送失败')
        }
      } catch (error) {
        console.error('回复发送失败:', error)
        ElMessage.error(error.message || '回复发送失败')
      } finally {
        replySubmitting.value = false
      }
    }
  })
}

// 申诉评价
const handleAppealReview = async (review) => {
  try {
    const { value: reason } = await ElMessageBox.prompt(
      `确认对此差评进行申诉？\n客户：${review.customerName}\n评分：${review.rating}星\n请输入申诉理由：`,
      '申诉确认',
      {
        confirmButtonText: '确认申诉',
        cancelButtonText: '取消',
        inputPlaceholder: '请输入申诉理由',
        inputValidator: (value) => {
          if (!value || value.trim().length === 0) {
            return '请输入申诉理由'
          }
          if (value.length < 10) {
            return '申诉理由至少10个字符'
          }
          return true
        }
      }
    )

    const response = await appealReview(review.id, {
      reason: reason,
      reviewContent: review.content,
      rating: review.rating
    })

    if (response.code === 200) {
      ElMessage.success('申诉已提交，平台将在3个工作日内处理')
      // 刷新评价列表
      await getReviewsData()
    } else {
      throw new Error(response.message || '申诉提交失败')
    }
  } catch (error) {
    if (error !== 'cancel') {
      console.error('申诉提交失败:', error)
      ElMessage.error(error.message || '申诉提交失败')
    }
  }
}

// 刷新评价
const refreshReviews = async () => {
  await getReviewStatsData()
  await getReviewsData()
  ElMessage.success('评价列表已刷新')
}

// 导出评价数据
const exportReviews = async () => {
  try {
    const params = {
      rating: filterRating.value !== 'all' ? filterRating.value : undefined,
      format: 'excel'
    }

    const response = await exportReviewsData(params)

    // 创建下载链接
    const blob = new Blob([response], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    })
    const url = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url
    link.download = `评价数据_${new Date().toISOString().slice(0, 10)}.xlsx`
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    window.URL.revokeObjectURL(url)

    ElMessage.success('评价数据导出成功')
  } catch (error) {
    console.error('导出评价数据失败:', error)
    ElMessage.error(error.message || '导出评价数据失败')
  }
}

// 监听评分筛选变化
watch(filterRating, async () => {
  currentPage.value = 1
  await getReviewsData()
})

// 页面初始化
onMounted(async () => {
  await getReviewStatsData()
  await getReviewsData()
>>>>>>> c61637f (所有前后端正常登录)
})
</script>

<style scoped>
<<<<<<< HEAD
.reviews-container {
  padding: 20px;
}
=======
.reviews-management {
  padding: 20px;
}

.stats-row {
  margin-bottom: 20px;
}

.stat-card {
  border-radius: 8px;
  overflow: hidden;
}

.stat-card.good {
  border-left: 4px solid #67c23a;
}

.stat-card.medium {
  border-left: 4px solid #e6a23c;
}

.stat-card.bad {
  border-left: 4px solid #f56c6c;
}

.stat-card.total {
  border-left: 4px solid #409eff;
}

.stat-content {
  display: flex;
  align-items: center;
  padding: 20px;
}

.stat-icon {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 15px;
  font-size: 20px;
  color: white;
}

.good .stat-icon {
  background: #67c23a;
}

.medium .stat-icon {
  background: #e6a23c;
}

.bad .stat-icon {
  background: #f56c6c;
}

.total .stat-icon {
  background: #409eff;
}

.stat-info {
  flex: 1;
}

.stat-number {
  font-size: 24px;
  font-weight: bold;
  color: #1f2937;
  margin-bottom: 5px;
}

.stat-label {
  font-size: 14px;
  color: #6b7280;
  margin-bottom: 3px;
}

.stat-rate {
  font-size: 12px;
  color: #9ca3af;
}

.reviews-card {
  border-radius: 8px;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.header-actions {
  display: flex;
  align-items: center;
}

.reviews-list {
  min-height: 400px;
}

.review-item {
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  padding: 20px;
  margin-bottom: 15px;
}

.review-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 15px;
}

.customer-info {
  flex: 1;
}

.customer-name {
  font-size: 16px;
  font-weight: 500;
  color: #1f2937;
  margin-bottom: 5px;
}

.order-info {
  font-size: 12px;
  color: #6b7280;
}

.review-meta {
  text-align: right;
}

.review-time {
  font-size: 12px;
  color: #9ca3af;
  margin-top: 5px;
}

.review-content {
  margin-bottom: 15px;
}

.review-text {
  font-size: 14px;
  color: #374151;
  line-height: 1.6;
  margin-bottom: 10px;
}

.review-tags {
  margin-bottom: 10px;
}

.review-tags .el-tag {
  margin-right: 8px;
  margin-bottom: 5px;
}

.review-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.action-buttons {
  display: flex;
  gap: 10px;
}

.merchant-reply {
  margin-top: 15px;
  padding: 15px;
  background: #f8fafc;
  border-radius: 6px;
  border-left: 3px solid #409eff;
}

.reply-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}

.reply-label {
  font-size: 14px;
  font-weight: 500;
  color: #409eff;
}

.reply-time {
  font-size: 12px;
  color: #9ca3af;
}

.reply-content {
  font-size: 14px;
  color: #374151;
  line-height: 1.6;
}

.empty-reviews {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 200px;
}

.reply-review-info {
  margin-bottom: 20px;
  padding: 15px;
  background: #f8fafc;
  border-radius: 6px;
}

.review-summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}

:deep(.el-card__header) {
  background: #fafbfc;
  border-bottom: 1px solid #e5e7eb;
}

:deep(.el-rate) {
  display: flex;
  align-items: center;
}

.pagination-wrapper {
  display: flex;
  justify-content: center;
  margin-top: 20px;
  padding: 20px 0;
}
>>>>>>> c61637f (所有前后端正常登录)
</style>